home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Media 20
/
PC MEDIA CD20.iso
/
share
/
prog
/
cursoasm
/
cap2.msg
< prev
next >
Wrap
Text File
|
1993-06-17
|
11KB
|
161 lines
INTRODUCCION AL ASM: EL 8086 Y LA ARQUITECTURA PC
=================================================
En este segundo capítulo del curso de ASM, veremos cómo difiere el 8086 de
la arquitectura ideal que vimos en el primer capítulo. Después, comenzaremos
a estudiar los registros del 8086.
El 8086, que es el uP que llevan los compatibles PC (todos los uP de la
serie 80x86 de Intel, los NEC V20 y V30, el Cyrix486, los AMD... son
totalmente compatibles con el 8086, es decir, reconocen el mismo juego de
códigos de operación, aunque incluyan algunos - o muchos - más), difiere
bastante del esquema que vimos en el capítulo anterior.
Lo primero es que los buses de direcciones y de datos tienen otra anchura:
20 bits para el bus de direcciones y 16 para el de datos. Cuando el uP genera
una lectura de memoria de la dirección x, se leen los bytes de la dirección (x)
y de la dirección (x+1), componiéndose con estos la palabra de 16 bits que se
envía al uP. En el 8086 y todos los uP Intel (y el Z80, y muchos otros), el
byte de la dir. (x) se usa para los 8 bits desde D0 hasta D7, y el de la dir.
(x+1) para los bits desde D8 hasta D15. Este ordenamiento de bytes se suele
denominar 'ordenamiento Intel' (adivinad por qué...), mientras que otros uP
como el Motorola MC68000 y los de su serie (usados en los Mac) usan el
'ordenamiento Motorola', en el que los bytes de una palabra (con una palabra
nos referimos al conjunto de dos bytes) se almacenan al reves en memoria.
El 8088 se diferenciaba del 8086 básicamente en que el bus de datos del uP
era de 8 bits, por lo que las lecturas de 16 bits debían realizarse en dos
pasos. A nivel de programación esto no se percibe, ya que una instrucción que
produzca una lectura de 16 bits se ejecuta igual pero tarda el doble, mientras
que la circuitería externa debe ser algo más complicada. Por lo demás, el 8088
lo consideraremos idéntico al 8086 y hablaremos únicamente de éste último. Las
VGA, por ejemplo, son dispositivos que añaden memoria a la propia del ordena-
dor, de manera que decir que una VGA es de 8 bits o de 16 indica si los accesos
a memoria de 16 bits se hacen en dos pasos, como en los ordenadores con 8088, o
en uno. Queda claro por qué el mismo programa corre mucho más rápido en una
VGA de 16 bits que en una de 8, siempre que el programa haga accesos a memoria
de palabra en palabra.
El problema que se presentó a los diseñadores del 8086 fue que los registros
internos del uP (el IP y muchos más que estudiaremos detalladamente más adelan-
te) debían ser de 16 bits, probablemente por limitaciones de diseño, mientras
que las direcciones que se envían por el bus de direcciones (y valga la redun-
dancia) debían ser de 20 bits. Para componer una dirección de memoria completa
son necesarios otros 4 bits además de los 16 de cada registro, ya que si estos
cuatro bits se ponen siempre al mismo valor sólo tendremos acceso a 64K de
memoria. La solución que se adopto ha venido limitando la accesibilidad de
memoria de los PCs desde entonces, y es la razón de que ahora mismo existan
cosas como la memoria extendida, la expandida, y otras peculiaridades que
suponen un gran handicap para los programas que corren en PCs frente a otros
ordenadores como los Mac.
La solución pasaba por añadir en el interior del micro varios registros de
16 bits llamados 'registros de segmento'. Son cuatro en el 8086 y el 286, y 2
más en el 386 y superiores. Aquí nos limitaremos a usar los del 8086, pero el
uso de los otros es idéntico en los 386+. La dirección completa de 20 bits se
forma a partir de un registro de segmento, que se elige en cada momento, y un
registro de 16 bits que se denomina 'desplazamiento' u 'offset'. Una de las
posibilidades hubiese sido tomar los 4 bits bajos del registro de segmento y
añadirles detrás los 16 del offset. Así compondríamos una dirección completa:
SEGMENTO | OFFSET
0000 0000 0000 1010 0101 1111 0000 1010
\ dir. completa /
1010 0101 1111 0000 1010 (20 bits)
De esta forma, los 4 bits bajos del segmento determinarían uno de los 16
bancos de 64K contenidos en un megabyte de memoria (el espacio direccionable
con 20 bits), y el offset determinaría la dirección en concreto a partir de la
dirección base de este segmento. Si el segmento fuera 0000h accederíamos a los
64K más bajos del megabyte, si fuera 0001h accederíamos a los 64K siguientes, y
así hasta un valor de segmento de 000Fh con el que accederíamos a los últimos
64K. Así, haciendo un símil en el que una carta de una baraja represente el
espacio de memoria accesible para cada valor de segmento, nuestra baraja (el
conjunto de todos los segmentos) está formada por 16 cartas, y está dispuesta
con cada carta junto a la otra sin superponerse, de manera que con todas las
cartas podemos acceder al mega completo de memoria. Con esta disposición a cada
posición de memoria sólo puede acceder por medio de una carta, y por tanto el
par segmento:offset que determina una dirección de memoria concreta es único.
Pero ya que los registros de segmento se hicieron de 16 bits, se eligió otra
forma de hacerlo de manera que se aprovechan totalmente los 16 bits del
segmento: lo que se hace para generar la dirección completa es desplazar el
segmento cuatro bits hacia la izquierda, rellenando los 4 bits de la derecha
con ceros, y sumarle al valor de 20 bits resultante el offset. El desplaza-
miento a la izquierda equivale a multiplicar por 16 o añadir un cero a la
derecha en hexadecimal:
/ valor de seg. \
16d x SEGMENTO 0000 0000 0000 1010 0000 <- 4 bits 'extra'
OFFSET 0101 1111 0000 1010
---------------------------------------
DIRECCION REAL 0000 0101 1111 1010 1010 (20 bits)
Así, el valor de segmento determina una dirección base (la formada por su
valor con los cuatro bits a cero), a partir de la cual el offset especifica
cuánto hay que moverse para hallar la dirección en concreto. Si meditamos un
poco sobre esto, podemos apreciar que cada segmento de 64K (que es el espacio
direccionable variando el offset y dejando el segmento fijo) se superpone con
otros segmentos. Ahora, volviendo al símil de la baraja, tenemos 64K (64*1024)
cartas, correspondientes a los 64K posibles diferentes valores de segmento.
También ahora podemos acceder al mega completo, pero las cartas están dispues-
tas no una al lado de la otra, sino que cada carta está dispuesta 16 posiciones
más a la derecha (o más arriba) que la anterior, de manera que se superpone a
la anterior casi en toda su extensión. Pero, como ya hemos dicho, la anchura
total de las cartas (la memoria total accesible) sigue siendo de un megabyte.
Así, una misma dirección real se puede generar a partir de diferentes valores
de segmento y offset. Por ejemplo, veamos la posición de memoria absoluta 17d
o 00011h. Esta dirección se puede especificar como valor de segmento 0 y offset
17d (0000:0011h), pero podemos apreciar que el par 0001:0001 también representa
la misma dirección absoluta. Para especificar una dirección por medio del seg-
mento y el offset se suele poner el valor del segmento (sin los cuatro bits que
se añaden a la derecha), dos puntos, y el valor de offset. Como segundo ejem-
plo, las direcciones 0040h:0000 y 0000:0400h son totalmente equivalentes y
ambas referencian la misma dirección absoluta de memoria, la 00400h o 1024d.
Para ir entrando un poco en cómo es el 8086 en concreto, recordaremos un
registro que ya mencionamos: el IP o 'Instruction Pointer', que contiene la
dirección de la siguiente instrucción a ejecutar. Este registro es de 16 bits,
por lo que necesitamos un registro de segmento para componer la dirección
completa de la siguiente instrucción. El segmento 'CS' o 'Code Segment' es el
registro con el que el uP compone la dirección completa de la siguiente
instrucción a recoger y ejecutar.
En un libro de programación en ASM tradicional, ahora veríamos el conjunto
completo de registros del 8086, la función de cada uno, etc... Estos libros,
además de para el aprendizaje, están pensados como referencia para el progra-
mador que ya conoce el micro o que ya conoce ASM de algún otro micro. Pero ya
que esto es un curso pensado para gente que nunca antes haya tenido contacto
con el lenguaje ensamblador, se seguirá otro orden: veremos primero algunos de
los registros, cuya función se puede comprender con los conocimientos adquiri-
dos hasta ahora, y a medida que se vayan introduciendo conceptos como la pila,
los saltos condicionales, etc... veremos el resto de los registros.
Todos los micros, incluyendo el menos potente, suelen tener un registro que
se utiliza de forma preferente para las operaciones aritméticas y lógicas.
Algunos micros, como el Z80, tienen algunas instrucciones que sólo pueden
ejecutarse con este registro. Este registro se suele denominar 'acumulador',
y en el 8086 toma el nombre simbólico de 'AX'. El 8086, además del AX,
incorpora otros tres registros denominados 'de propósito general', con los que
también se pueden hacer algunas operaciones aritméticas. Pero, por ejemplo, las
multiplicaciones o divisiones sólo se pueden hacer con el AX. Los otros
registros también presentan peculiaridades, instrucciones que operan sobre un
registro determinado, pero las iremos viendo sobre la marcha. Estos otros tres
registros se representan mediante los nombres 'BX', 'CX' y 'DX', y son todos
de 16 bits.
Para componer direcciones de memoria, además del CS que se usa principal-
mente para complementar al IP, existen otros registros de segmento. Por el
momento describiremos dos de los otros tres que existen, el 'DS' (Data
Segment) y el 'ES' (Extra Segment). Cuando leemos datos de la memoria, dando
la dirección de la que leer por medio de un registro, por defecto se construye
la dirección completa usando el DS, aunque se puede especificar en la instruc-
ción si se quiere usar el ES o el CS en su lugar.
En el siguiente capítulo veremos la primera instrucción de ASM, la más
usada, la instrucción 'MOV'. Y comentaremos algunas cosillas de cómo empezar
a experimentar con el ASM sin más que el DEBUG del MS-DOS.
Salut!!! :-)
Jon